<html>
<head>
  <title>Evernote Export</title>
  <basefont face="微软雅黑" size="2" />
  <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
  <meta name="exporter-version" content="YXBJ Windows/602498 (zh-CN, DDL); Windows/10.0.0 (Win64); EDAMVersion=V2;"/>
  <style>
    body, td {
      font-family: 微软雅黑;
      font-size: 10pt;
    }
  </style>
</head>
<body>
<a name="537"/>

<div>
<span><div><div><br/></div><div><br/></div><div><br/></div><div>Mybatis： 是一个优秀的基于ORM的半自动轻量级持久层框架，它对jdbc的操作数据库的过程进行封装， 使开发者只需要关注 SQL 本身，而不需要花费精力去处理例如注册驱动、创建connection、创建 statement、手动设置参数、结果集检索等jdbc繁杂的过程代码</div><div><br/></div><div>ORM（ 对象关系映射 ）思想</div><div><br/></div><div>O（对象模型）： 实体对象，即我们在程序中根据数据库表结构建立的一个个实体javaBean</div><div>R（关系型数据库的数据结构）： 关系数据库领域的Relational（建立的数据库表）</div><div>M（映射）： 从R（数据库）到O（对象模型）的映射，可通过XML文件映射</div><div>        </div><div>如何实现：</div><ol><li><div>让实体类和数据库表进行一一对应关系</div></li><li><div>不需要直接操作数据库表，直接操作表对应的实体类对象</div></li></ol><div><br/></div><div><br/></div><div>代码流程：</div><ol><li><div>创建数据库及表</div></li><li><div>创建maven工程，导入依赖（MySQL驱动、mybatis、junit）</div></li><li><div>编写pojo类</div></li><li><div>编写映射配置文件（ORM思想）</div></li><li><div>编写SqlMapConfig.xml核心配置文件</div></li><ol><li><div>数据库环境配置</div></li><li><div>映射关系配置的引入(引入映射配置文件的路径)</div></li></ol><li><div>编写测试代码</div></li></ol><div><br/></div><div><br/></div><div>MyBatis核心配置文件需要配置的信息</div><ol><li><div>环境配置  使用MySQL环境</div></li><li><div>使用JDBC类型事务管理器</div></li><li><div>使用连接池</div></li><li><div><span style="color: rgb(255, 0, 0);">加载映射配置</span></div></li></ol><div><br/></div><div>Mybatis映射文件概述：</div><ol><li><div>跟标签&lt;mapper namespace=&quot;&quot;&gt;</div></li><li><div>增删改查操作 &lt;insert&gt; &lt;delete&gt; &lt;update&gt; &lt;selete&gt;</div></li><li><div>parameterType:   指定要插入的数据类型</div></li><li><div>Sql语句中使用#{实体属性名}方式引用实体中的属性值</div></li><li><div>如果操作中会改变数据 要使用 sqlSession对象显示的提交事务，即 <a href="http://sqlsession.commit/">sqlSession.commit</a>()</div></li></ol><div><br/></div><div><br/></div><div><span style="font-size: unset; color: unset; font-family: unset;">    </span> MyBatis核心配置文件层级关系</div><div>配置文档的顶层结构如下：</div><div><br/></div><div>                  </div><div><span style="font-size: unset;"><br/></span></div><div><span style="font-size: unset;"><br/></span></div><div>environments标签</div><div><br/></div><div><br/></div><div><span style="font-size: unset;"><br/></span></div><div>事务管理器（transactionManager）类型有两种：</div><ol><li><div>JDBC： 这个配置就是直接使用了JDBC 的提交和回滚设置，它依赖于从数据源得到的连接来管理事务作用域。</div></li><li><div>MANAGED： 这个配置几乎没做什么。它从来不提交或回滚一个连接，而是让容器来管理事务的整个生命周期。 例如：mybatis与spring整合后，事务交给spring容器管理。</div></li></ol><div><br/></div><div><br/></div><div>数据源（dataSource）常用类型有三种：</div><div><span style="font-size: unset;"><br/></span></div><div>UNPOOLED： 这个数据源的实现只是每次被请求时打开和关闭连接。</div><div>POOLED： 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来。</div><div>JNDI : 这个数据源实现是为了能在如 EJB 或应用服务器这类容器中使用，容器可以集中或在外部配置数据 源，然后放置一个 JNDI 上下文的数据源引用</div><div><span style="font-size: unset;"><br/></span></div><div><span style="font-size: unset;"><br/></span></div><div>properties标签： 实际开发中，习惯将数据源的配置信息单独抽取成一个properties文件，该标签可以加载额外配置的 properties：</div><div><br/></div><div>typeAliases标签：设置别名  简化映射文件 Java 类型设置</div><div><br/></div><div>mappers标签：加载映射文件在核心配置文件中使用</div><div><br/></div><div><br/></div><div><span style="font-size: unset;"><br/></span></div><div><span style="font-size: unset;"><br/></span></div><div><span style="font-size: unset;"><br/></span></div><div>Mybatis的API概述</div><div><span style="font-size: unset;"><br/></span></div><div><span style="font-size: unset;"><br/></span></div><div><span style="font-size: unset; color: unset; font-family: unset;">Mybatis配置文件的基本原理(他的底层就是执行JDBC，只不过就是对JDBC进行了封装)</span></div><div><br/></div><div>SqlMapConfig.xml :核心配置文件：数据源，事务，引人映射配置文件</div><div>映射配置文件：主要配置了要执行的sql语句，传入参数，传出参数等</div><div>new SqlSessionFactoryBuilder().build()</div><ol><li><div>进行了初始化配置：使用dom4j解析了配置文件，将映射配置文件中的配置封装了一个一个的MappedStatemend对象,将这些MappedStatemend对象封装成map集合</div></li><li><div>创建了了sqlSessionFactory工厂对象</div></li></ol><div><br/></div><div>Sqlsession:会话对象 ：本身并不会直接操作数据库，他会委派给执行器来操作Sqlsession.selectList()</div><div>Executor执行器执行JDBC代码时首先要获取MappedStatemend对象 才能正常的去执行JDBC（执行JDBC所需要的信息都在MappedStatemend对象中）</div><div><br/></div><div>操作事务的方法主要有： void commit()         void rollback()</div><div><br/></div><div>代理开发方式: 采用 Mybatis 的基于接口代理方式实现 持久层 的开发，这种方式是我们后面进入企业的主流。 基于接口代理方式的开发只需要程序员编写 Mapper 接口，Mybatis 框架会为我们动态生成实现类的对 象。</div><div>代理开发方式规范：</div><ol><li><div>Mapper.xml映射文件中的namespace与mapper接口的全限定名相同</div></li><li><div>Mapper接口方法名和Mapper.xml映射文件中定义的每个statement的id相同</div></li><li><div>Mapper接口方法的输入参数类型和mapper.xml映射文件中定义的每个sql的parameterType的类 型相同</div></li><li><div>Mapper接口方法的输出参数类型和mapper.xml映射文件中定义的每个sql的resultType的类型相 同</div></li></ol><div><br/></div><div>Mybatis基于接口代理方式的内部执行原理：</div><div>我们的持久层现在只有一个接口，而接口是不实际干活的</div><div>因为 我们使用的mapper实际上是一个代理对象,是由MapperProxy代理产生的。</div><div><br/></div><div><br/></div><div><font style="font-size: 18pt;"><span style="color: rgb(227, 0, 0); font-family: 仿宋; font-size: 18pt; font-weight: bold;">复杂映射&amp;配置文件深入</span></font></div><div><br/></div><div>Mybatis高级查询</div><div>建立对象关系映射</div><ol><li><div>resultType  如果实体的属性名与表中字段名一致，将查询结果自动封装到实体类中</div></li><li><div>ResutlMap 如果实体的属性名与表中字段名不一致，可以使用ResutlMap实现手动封装到实体类中</div></li></ol><div><br/></div><div><br/></div><div>多条件查询</div><ol><li><div>方式一： 使用 #{arg0}-#{argn} 或者 #{param1}-#{paramn} 获取参数 </div></li><li><div>方式二：使用注解，引入 @Param() 注解获取参数</div></li><li><div><span style="color: rgb(227, 0, 0);">方式三： 使用pojo对象传递参数（推荐该方式）</span></div></li></ol><div>模糊查询时 在编写测试代码时传入的参数中参数两边使用%包起来</div><div><br/></div><div><br/></div><div><span style="font-size: unset; color: unset; font-family: unset;">${} 与 #{} 区别</span></div><div>${} :表示拼接sql串</div><ol><li><div>通过 ${} 可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换，会出现sql注入 问题。</div></li><li><div>${} 可以接收简单类型值或pojo属性值。</div></li><li><div>如果parameterType传输单个简单类型值， ${} 括号中只能是value。</div></li></ol><div><br/></div><div>#{} :表示一个占位符号</div><ol><li><div>通过 #{} 可以实现preparedStatement向占位符中设置值，自动进行java类型(实体类属性类型)和jdbc类型(数据库表中字段类型)转换，# {}可以有效防止sql注入。</div></li><li><div>#{} 可以接收简单类型值或pojo属性值。</div></li><li><div>如果parameterType传输单个简单类型值， #{} 括号中名称随便写。</div></li></ol><div><br/></div><div>返回主键（ 只适用于主键自增的数据库，mysql和sqlserver支持，oracle不行。 ）</div><div>方法： </div><ol><li><div>useGeneratedKeys=&quot;true&quot; 声明返回主键</div></li><li><div>keyProperty=&quot;id&quot; 把返回主键的值，封装到实体的id属性中</div></li></ol><div><br/></div><div><br/></div><div>selectKey： 在映射文件的增删改查标签中使用</div><ol><li><div>selectKey 适用范围广，支持所有类型数据库</div></li><li><div>keyColumn=&quot;id&quot; 指定主键列名</div></li><li><div>keyProperty=&quot;id&quot; 指定主键封装到实体的id属性中</div></li><li><div>resultType=&quot;int&quot; 指定主键类型</div></li><li><div>order=&quot;AFTER&quot; 设置在sql语句执行前（后），执行此语句</div></li></ol><div><br/></div><div><br/></div><div>动态SQL：</div><div><br/></div><div>应用场景; 当我们要根据不同的条件，来执行不同的sql语句的时候，需要用到动态sql。</div><div><br/></div><div>动态 SQL 之&lt;if&gt;</div><div>eg: 根据id和username查询，但是不确定两个都有值。</div><div><br/></div><div>在映射配置文件中的增删改查的标签中编写</div><div><br/></div><div>eg:</div><div><br/></div><div><br/></div><div>where标签相当于1=1 如果没有条件 就不会拼接where关键字</div><div><br/></div><div><br/></div><div><br/></div><div>动态sql值&lt;set&gt;:在映射配置文件中的增删改查的标签中编写</div><div>eg:</div><div><br/></div><div><br/></div><div><br/></div><div>set标签在更新的时候，自动加上set关键字，然后去掉最后一个条件的逗号</div><div><br/></div><div>动态sql之&lt;foreach&gt;  在增删改查中使用</div><div><br/></div><div>eg: select * from user where id in (1,2,3) 在这样的语句中，传入的参数部分必须依靠 foreach遍历才能实现。</div><div><br/></div><div>&lt;foreach&gt;标签用于遍历集合 它的属性：</div><ol><li><div> collection：代表要遍历的集合元素</div></li><li><div>open：代表语句的开始部分</div></li><li><div>close：代表结束部分</div></li><li><div>item：代表遍历集合的每个元素，生成的变量名</div></li><li><div>sperator：代表分隔符</div></li></ol><div><br/></div><div><br/></div><div><br/></div><div>注：如果查询条件为普通类型 List集合，collection属性值为：collection 或者 list</div><div><br/></div><div><br/></div><div>MyBatis一级缓存</div><div><br/></div><div>使用的是同一个sqlSession操作，当第一次查询时首先会查询一级缓存，缓存中没有数据，第一次就会查询数据库</div><div>第二次查询时，同样会先查询一级缓存<span style="font-size: unset; color: unset; font-family: unset;">，此时一级缓存中有数据就无需查询数据库</span></div><div><br/></div><div><span style="font-size: unset; color: unset; font-family: unset;">何时会清空一级缓存？ 在第二次查询之前进行了增删改操作 或者调用clearCache()   commit()  close()  方法，都会清空缓存，此时第二次查询中一级缓存中没有数据了，此时第二次查询的是数据库 ，此时第二次查询的结果是增删改操作的数据</span></div><div><br/></div><div><br/></div><div><br/></div><div>MyBatis嵌套查询： 嵌套查询就是将原来多表查询中的联合查询语句拆成单个表的查询，再使用mybatis的语法嵌套在一 起。</div><div><br/></div><div>一对一配置：使用&lt; resultMap &gt;+&lt; association &gt;做配置，通过column条件，执行select查询</div><div>一对多配置：使用&lt; resultMap &gt;+&lt; collection &gt;做配置，通过column条件，执行select查询</div><div>多对多配置：使用&lt; resultMap &gt;+&lt; collection &gt;做配置，通过column条件，执行select查询</div><div><br/></div><div>优点：简化多表查询操作</div><div>缺点：执行多次sql语句，浪费数据库性能</div><div><br/></div><div><br/></div><div><font style="font-size: 16pt;"><span style="color: rgb(227, 0, 0); font-family: 华文仿宋; font-size: 16pt; font-weight: bold;">加载策略及注解开发</span></font></div><div><font style="font-size: 16pt;"><br/></font></div><div><br/></div><div>MyBatis加载策略</div><div><span style="font-size: unset; color: unset; font-family: unset;">什么是延迟加载？ 就是在需要用到数据时才进行加载，不需要用到数据时就不加载数据。延迟加载也称懒加载</span></div><div>延迟加载优点： 先从单表查询，需要时再从关联表去关联查询，大大提高数据库性能，因为查询单表要比关联查询多张表 速度要快。</div><div>缺点： 因为只有当需要用到数据时，才会进行数据库查询，这样在大批量数据查询时，因为查询工作也要消耗时 间，所以可能造成用户等待时间变长，造成用户体验下降。</div><div><span style="color: rgb(227, 0, 0);">注意： 延迟加载是基于嵌套查询来实现的</span></div><div><span style="background-color: rgb(43, 43, 43);"><font style="font-size: 10pt;"><br/></font></span></div><div>局部延迟加载： 在association和collection标签中都有一个fetchType属性，通过修改它的值，可以修改局部的加载策 略。</div><div><br/></div><div>设置触发延迟加载的方法： 大家在配置了延迟加载策略后，发现即使没有调用关联对象的任何方法，但是在你调用当前对象的 equals、clone、hashCode、toString方法时也会触发关联对象的查询。</div><div>我们可以在配置文件中使用lazyLoadTriggerMethods配置项覆盖掉上面四个方法。</div><div><br/></div><div>全局延迟加载： 在Mybatis的核心配置文件中可以使用setting标签修改全局的加载策略。</div><div><br/></div><div><br/></div><div>注意; 局部的加载策略优先级高于全局的加载策略。</div><div><br/></div><div>MyBatis缓存:</div><div><br/></div><div>为什么使用缓存？ 当用户频繁查询某些固定的数据时,第一次将这些数据从数据库中查询出来,保存在缓存中。当用户再 次查询这些数据时,不用再通过数据库查询,而是去缓存里面查询。减少网络连接和数据库查询带来的损 耗,从而提高我们的查询效率,减少高并发访问带来的系统性能问题。</div><div>一句话概括：经常查询一些不经常发生变化的数据，使用缓存来提高查询效率。</div><div>像大多数的持久化框架一样，Mybatis也提供了缓存策略，通过缓存策略来减少数据库的查询次数， 从而提高性能。 Mybatis中缓存分为一级缓存，二级缓存。</div><div><br/></div><div><br/></div><div>一级缓存: 一级缓存是SqlSession级别的缓存，是默认开启的</div><div>所以在参数和SQL完全一样的情况下，我们使用同一个SqlSession对象调用一个Mapper方法，往往 只执行一次SQL，因为使用SelSession第一次查询后，MyBatis会将其放在缓存中，以后再查询的时 候，如果没有声明需要刷新，并且缓存没有超时的情况下，SqlSession都会取出当前缓存的数据，而不 会再次发送SQL到数据库。</div><div><br/></div><div>分析： 一级缓存是SqlSession范围的缓存，执行SqlSession的C（增加）U（更新）D（删除）操作，或者调 用clearCache()、commit()、close()方法，都会清空缓存。</div><div><br/></div><div>二级缓存： 二级缓存是namspace级别（跨sqlSession）的缓存，是默认不开启的</div><div>二级缓存的开启需要进行配置，实现二级缓存的时候，MyBatis要求返回的POJO必须是可序列化的。 也就是要求实现Serializable接口，配置方法很简单，只需要在映射XML文件配置 &lt;cache/&gt;就可以开启 二级缓存了。</div><div><br/></div><div>分析： 二级缓存是mapper映射级别的缓存，多个SqlSession去操作同一个Mapper映射的sql语句，多个 SqlSession可以共用二级缓存，二级缓存是跨SqlSession的。</div><div><br/></div><div>注意问题（脏读）： mybatis的二级缓存因为是namespace级别，所以在进行多表查询时会产生脏读问题</div><div><br/></div><div>总结：</div><ol><li><div>mybatis的缓存，都不需要我们手动存储和获取数据。mybatis自动维护的。</div></li><li><div>mybatis开启了二级缓存后，那么查询顺序：二级缓存--》一级缓存--》数据库</div></li><li><div>注意：mybatis的二级缓存会存在脏读问题，需要使用第三方的缓存技术解决问题。</div></li></ol><div><br/></div><div><br/></div><div>MyBatis注解</div><div>MyBatis常用注解</div><ol><li><div>* @Insert：实现新增，代替了&lt;insert&gt;&lt;/insert&gt;</div></li><li><div>* @Delete：实现删除，代替了&lt;&gt;&lt;&gt;</div></li><li><div>@Update：实现更新，代替了</div></li><li><div>* @Select：实现查询，代替了</div></li><li><div>@Result：实现结果集封装，代替了</div></li><li><div>@Results：可以与@Result 一起使用，封装多个结果集，代替了&lt;resultmap&gt;&lt;/resultmap&gt;</div></li><li><div>@One：实现一对一结果集封装，代替了&lt;association&gt;&lt;/association&gt;</div></li><li><div>@Many：实现一对多结果集封装，代替了&lt; collection &gt;&lt;/ collection &gt;</div></li></ol><div><br/></div><div><br/></div><div>使用注解实现复杂映射开发: 使用注解开发后，我们可以使用 @Results、@Result，@One、@Many 注解组合完成复杂关系的配置。</div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div>在Mapper接口中使用注解配置二级缓存:</div><div>@CacheNamespace </div><div>public interface UserMapper {...}</div><div><br/></div><div><br/></div><div>注解延迟加载: 不管是一对一还是一对多 ，在注解配置中都有fetchType的属性</div><ol><li><div>fetchType = FetchType.LAZY 表示懒加载</div></li><li><div>fetchType = FetchType.EAGER 表示立即加载</div></li><li><div>fetchType = FetchType.DEFAULT 表示使用全局配置</div></li></ol><div><br/></div><div>总结：</div><div><br/></div><div>注解开发和xml配置优劣分析</div><ol><li><div>注解开发和xml配置相比，从开发效率来说，注解编写更简单，效率更高。</div></li><li><div>从可维护性来说，注解如果要修改，必须修改源码，会导致维护成本增加。xml维护性更强。</div></li></ol><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div></div><div><br/></div></span>
</div></body></html> 